package main

//   killall S999LingMaxDns;killall LingMaxDns_linux_mipsle;cd /etc/;wget -O LingMaxDns_linux_mipsle1  http://192.168.1.236/LingMaxDns_linux_mipsle ;mv LingMaxDns_linux_mipsle1 LingMaxDns_linux_mipsle  ; chmod 777 LingMaxDns_linux_mipsle;/etc/LingMaxDns_linux_mipsle &
import (
	"context"
	"encoding/binary"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"runtime"
	"sort"
	"strings"
	"sync"
	"time"

	"strconv"

	"net"

	"golang.org/x/net/dns/dnsmessage"
)

var fmt = log.New(os.Stderr, "", 0)
var logger = log.New(os.Stderr, "httpsproxy:", log.Llongfile|log.LstdFlags)

// 域名信息
type HostInfo struct {
	ips   map[string]int64  //ip数组ips
	utime int64             //更新时间
	ysip  map[string]string //本地dns解析的ip
}

// IP信息
type DNSADDR struct {
	buf  *[]byte //FNS查询ID
	addr *net.UDPAddr
}

// IP信息
type IpInfo struct {
	tcpMs  int64 //tcp响应时间
	httpMs int64 //http响应时间
	pingMs int64 //ping响应时间
	ms     int64 //最终响应时间
	utime  int64 //更新时间
}

type ipMs struct {
	ip string //ip
	ms int64  //响应时间
}

var HOST = map[string]*HostInfo{}
var IPS = map[string]*IpInfo{}
var lock = sync.Mutex{}
var DNSREQ = []*DNSADDR{}

var TCPDNS = map[string]string{
	"208.67.222.222":  "53",
	"114.114.114.114": "53",
	"223.5.5.5":       "53",
	"219.232.32.99":   "53",
	"222.18.224.1":    "53",
	"222.199.6.1":     "53",
	"168.95.192.1":    "53",
	"210.76.0.2":      "53",
	"60.10.57.234":    "53",
	"221.232.129.35":  "53",
	"218.69.96.12":    "53",
	"202.106.84.253":  "53",
	"219.222.48.5":    "53",
	"60.191.123.52":   "53",
	"211.161.103.214": "53",
	"202.175.113.124": "53",
	"202.180.160.1":   "53",

	"187.130.63.137": "53",
	"137.82.1.1":     "53",
	"204.70.127.127": "53",
	"205.171.2.65":   "53",
	"210.48.77.69":   "53",
	"212.77.217.193": "53",
	"180.92.170.100": "53",
	"202.248.20.133": "53",
	"202.56.128.30":  "53",
	"219.252.0.1":    "53",
	"103.22.248.62":  "53",
	"183.78.169.111": "53",
	"110.35.78.66":   "53",
}

func main() {
	runtime.GOMAXPROCS(6)
	var all_port = 8287 //监听端口

	Exedir, r2ee := os.Executable()

	fmt = logger
	logger.Println("启动..请稍候  -P53 指定使用53端口(默认8287)", Exedir)
	for _, v := range os.Args {
		if v == "-E" {
			Exedir = ""
		}
		if v == "-P53" {
			all_port = int(53)
		}
		//i = i
	}
	if r2ee == nil && Exedir != "" {

		var cmd *exec.Cmd
		for {
			fmt.Println("-E 子进程启动中...", Exedir)
			if all_port == 53 {
				cmd = exec.Command(Exedir, "-E", "-P53")
			} else {
				cmd = exec.Command(Exedir, "-E")
			}

			cmd.Start()
			cmd.Wait()
		}
	}

	serverDNS, err2 := net.ListenUDP("udp", &net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: all_port})
	if err2 != nil {
		fmt.Println("端口监听失败", all_port, err2)
		os.Exit(1)
	}
	defer serverDNS.Close()
	etime := timems() + 1000*60*30
	utime := timems() + 1000*10
	for {
		if etime < timems() {
			os.Exit(1)
		}

		buf := make([]byte, 2048)
		serverDNS.SetReadDeadline((time.Now().Add(1 * time.Millisecond)))
		n, addr, errx := serverDNS.ReadFromUDP(buf)
		if !(errx != nil || n < 3) {
			buf = buf[:n]
			go dnsmsg(buf, addr)
		}
		goc(func() {
			for i := 0; i < len(DNSREQ); i++ {
				serverDNS.WriteToUDP(*DNSREQ[i].buf, DNSREQ[i].addr)
			}
			DNSREQ = []*DNSADDR{}
		})

		if utime > timems() {
			continue
		}
		goc(func() {
			// 请求垃圾回收
			runtime.GC()
			tt := timems() + 1000*10
			for ip, v := range IPS {
				if v.utime+1000*60*30 < tt {
					delete(IPS, ip)
				}
			}
			for host, v1 := range HOST {
				if v1.utime+1000*60*30 < tt {
					delete(HOST, host)
				} else {
					for ip, v2 := range v1.ips {
						if v2+1000*60*30 < tt {
							delete(v1.ips, ip)
						}
					}
				}
			}
		})

	}
}

// 转发DNS请求
func dnsmsg(buf []byte, addr *net.UDPAddr) {
	host := goDNS(buf) //解析DNS请求
	dns119x, _ := net.ResolveUDPAddr("udp4", "119.29.29.29:53")
	dns119server, err := net.ListenUDP("udp", &net.UDPAddr{}) // 本地随机端口
	if err != nil {
		return
	}
	defer dns119server.Close()
	dns119server.WriteToUDP(buf, dns119x)
	dns119server.SetReadDeadline((time.Now().Add(2 * 1000 * time.Millisecond)))

	buf2 := make([]byte, 4096)
	n, _, err := dns119server.ReadFromUDP(buf2)
	if err != nil || n < 3 {
		dns114, _ := net.ResolveUDPAddr("udp4", "8.8.8.8:53")
		dns119server2, err2 := net.ListenUDP("udp", &net.UDPAddr{}) // 本地随机端口
		if err2 != nil {
			return
		}
		defer dns119server2.Close()
		dns119server2.WriteToUDP(buf, dns114)
		dns119server2.SetReadDeadline((time.Now().Add(4 * 1000 * time.Millisecond)))
		buf2 = make([]byte, 4096)
		n, _, err = dns119server2.ReadFromUDP(buf2)
		if err != nil || n < 3 {
			return
		}
	}
	buf2 = buf2[:n]
	go UnpackDNSMessage(host, buf2) //第一次查询也要测速
	buf2 = replaceDns(host, buf2)   //替换数据包
	goc(func() {
		DNSREQ = append(DNSREQ, &DNSADDR{buf: &buf2, addr: addr})
	})
}

func localDns(host string) {
	// 创建一个带有超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()

	// 创建一个 Resolver 对象
	resolver := net.Resolver{}

	// 使用 Resolver 对象进行主机名解析
	ipsxx, err := resolver.LookupHost(ctx, host)

	// ipsxx, errxx := net.LookupHost(host)
	if err != nil {
		return
	}
	ysip := map[string]string{}

	for _, ipxx := range ipsxx {
		ysip[ipxx] = ipxx
		go checkIp(host, ipxx)
	}
	goc(func() {
		sethost(host)
		HOST[host].ysip = ysip
	})
}

// 替换数据包
func replaceDns(host string, buf []byte) []byte {
	ipv4x := ""
	ht := int64(1)

	for i := 0; i < 30; i++ { //10*50=500ms
		goc(func() {
			sethost(host)
			if HOST[host].utime+1000*3 < timems() {
				ht = HOST[host].utime
				for _, ipxx := range HOST[host].ysip {
					setips(ipxx)
					if IPS[ipxx].ms > 0 && IPS[ipxx].ms < 53 {
						ipv4x = ipxx //本地dns解析的ip 延迟低于53ms 直接返回 运营商优化过了的
						break
					}
				}
			}
		})
		if ipv4x != "" {
			break
		}
		ipv4x = getHost2Ipv4(host)
		if ipv4x != "" {
			break
		}
		if ht == 0 { //首次需要等待
			time.Sleep(10 * time.Millisecond)
		} else {
			break
		}
	}

	goc(func() {
		sethost(host)
		if HOST[host].utime+1000*30 < timems() {
			HOST[host].utime = timems()
			if ipv4x == "" {
				queryDns(host, buf)
			} else {
				go checkIp(host, ipv4x)
				go localDns(host) //本地dns解析
			}

		}
	})

	var msg dnsmessage.Message
	err := msg.Unpack(buf)
	if err != nil {
		return buf
	}

	// return buf
	isIp := false
	for i := 0; i < len(msg.Answers); i++ {
		if dnsmessage.TypeA == msg.Answers[i].Header.Type && ipv4x != "" {
			msg.Answers[i].Header.TTL = 10
			msg.Answers[i].Header.Class = dnsmessage.ClassINET
			msg.Answers[i].Body.(*dnsmessage.AResource).A = ipToByte(ipv4x)
			// cname, cerr := dnsmessage.NewName(host)
			// if cerr == nil {
			// 	msg.Answers[i].Header.Name = cname
			// }
			isIp = true
			// msg.Header.RecursionDesired = true // 设置RD标志，表示递归查询
			// msg.Header.Questions = append(msg.Header.Questions, dnsmessage.Question{
			// 	Name:  dnsmessage.MustNewName(host),
			// 	Type:  dnsmessage.TypeA, // 设置查询类型为AAAA
			// 	Class: dnsmessage.ClassINET,
			// })

			// msg.Answers = []dnsmessage.Resource{msg.Answers[i], msg.Answers[i]}
			// break
		}
	}
	if isIp {
		buf3, err := msg.Pack()
		if err != nil {
			return buf
		}
		// goc(func() {
		// 	setips(ipv4x)
		// 	fmt.Println("解析成功:", host, ipv4x, "延迟", IPS[ipv4x].ms)
		// })
		return buf3 //只返回一个A记录
	}
	return buf

}

func ipToByte(ip string) [4]byte {
	a := [4]byte{0, 0, 0, 0}
	ips := strings.Split(ip, ".")
	if len(ips) != 4 {
		return a
	}
	for i := 0; i < len(ips); i++ {
		xi, _ := strconv.Atoi(ips[i])
		a[i] = byte(xi)
	}
	return a
}

// 解析DNS请求
func goDNS(buf []byte) string {
	var msg dnsmessage.Message
	err := msg.Unpack(buf)
	if err != nil {
		return ""
	}
	if len(msg.Questions) < 1 {
		return ""
	}
	question := msg.Questions[0]
	if dnsmessage.TypeA != question.Type {
		return ""
	}
	host := question.Name.String()
	if len(host) < 3 {
		return ""
	}
	if string(host[0]) == "." {
		host = host[1:]
	}
	if string(host[len(host)-1]) == "." {
		host = host[:len(host)-1]
	}
	if len(host) < 3 {
		return ""
	}

	goc(func() {
		sethost(host)
		if HOST[host].utime < 1 {
			HOST[host].utime = timems()
			queryDns(host, buf)
			// go localDns(host) //本地dns解析
		}
	})

	return host
}

func queryDns(host string, buf []byte) {
	if len(buf) < 3 {
		return
	}
	s0 := string(buf[0])
	if s0 == "\x00" && s0 == "." {
		return
	}
	sleep := 0
	//UDP协议转TCP协议
	bufLen := make([]byte, 2)
	binary.BigEndian.PutUint16(bufLen, uint16(len(buf)))
	tcpbuf := append(bufLen, buf...)
	//万一以后不更新程序了 直接请求 我的服务器动态获取节点
	go host2ipHttp(host, "", "alidns.lingmax.top", "80", sleep)
	for ip, port := range TCPDNS {
		sleep++
		go TcpDNS(host, ip, port, tcpbuf, sleep)
		go host2ipHttp(host, ip, "223.6.6.6", "80", sleep)
	}

	go localDns(host) //本地dns解析
	// var ms runtime.MemStats
	// runtime.ReadMemStats(&ms)
	// mem := int((ms.Alloc/1024/1024)*10) / 10
	// fmt.Println("查询DNS:", host, "当前协程数:", runtime.NumGoroutine(), "当前内存占用:", mem, "MB")
}

// DNS查询 内存查询
func getHost2Ipv4(host string) string {
	if len(host) < 3 {
		return ""
	}
	if string(host[0]) == "." {
		host = host[1:]
	}
	if string(host[len(host)-1]) == "." {
		host = host[:len(host)-1]
	}
	ipv4 := ""
	goc(func() {
		_, ok := HOST[host]
		if !ok {
			return
		}
		d1 := []ipMs{}
		for ip, _ := range HOST[host].ips {
			v, ok2 := IPS[ip]
			if !ok2 || v.ms < 1 {
				continue
			}
			d1 = append(d1, ipMs{ms: v.ms, ip: ip})
		}
		if len(d1) < 1 {
			return
		}
		sort.Slice(d1, func(i, j int) bool {
			return d1[i].ms < d1[j].ms
		})

		ipv4 = d1[0].ip

		for _, vv := range d1 {
			rand.Seed(time.Now().UnixNano()) //设置随机数种子
			min := 1
			max := 20
			randomNum := rand.Intn(max-min) + min
			if randomNum > 10 || vv.ip == ipv4 {
				continue
			}
			if vv.ms < d1[0].ms+50 { //如果相差不超过50ms则随机安排
				ipv4 = vv.ip
			}
		}

	})

	return ipv4
}

func setMs(v *IpInfo) int64 {
	ms := int64(0)
	if v.httpMs > 0 {
		ms = v.httpMs //http优先
	} else if v.tcpMs > 0 {
		ms = v.tcpMs * 1 //tcp次之 2倍延迟
	} else if v.pingMs > 0 {
		ms = v.pingMs * 1 //ping最后 2倍延迟
	}
	v.ms = ms
	return ms
}

// TCPDNS查询
func TcpDNS(host string, ip string, port string, tcpbuf []byte, sleep int) {
	time.Sleep(time.Duration(sleep) * time.Nanosecond)
	// return //暂时不用

	conn, err := net.DialTimeout("tcp", ip+":"+port, 2*1000*time.Millisecond) // 3s timeout
	if err != nil {
		return
	}
	defer conn.Close()
	conn.Write(tcpbuf)
	conn.SetReadDeadline((time.Now().Add(2 * 1000 * time.Millisecond)))
	buf := make([]byte, 2048)
	len1, err := conn.Read(buf)
	if err != nil || len1 < 3 {
		return
	}
	buf = buf[:len1]
	buf = buf[2:] // tcp包转UDP包
	go UnpackDNSMessage(host, buf)
}

// 解析DNS结果
func UnpackDNSMessage(host string, buf []byte) {
	var msg dnsmessage.Message
	err := msg.Unpack(buf)
	if err != nil {
		return
	}
	ysip := map[string]string{}
	for i := 0; i < len(msg.Answers); i++ {
		if dnsmessage.TypeA != msg.Answers[i].Header.Type {
			continue // 只处理A记录
		}
		b := msg.Answers[i].Body.(*dnsmessage.AResource).A
		if len(b) < 4 {
			continue // 无效的A记录
		}
		ipv4 := strconv.Itoa(int(b[0])) + "." + strconv.Itoa(int(b[1])) + "." + strconv.Itoa(int(b[2])) + "." + strconv.Itoa(int(b[3]))
		go checkIp(host, ipv4)
		ysip[ipv4] = ipv4
	}
	goc(func() {
		sethost(host)
		if len(HOST[host].ysip) < 1 {
			HOST[host].ysip = ysip //设置默认原始ip
		}
	})
}

// 检查IP是否有效
func checkIp(host string, ip string) {
	ipx := net.ParseIP(ip)
	if ipx == nil || ipx.To4() == nil {
		return // 解析失败，不是有效的 IP 地址
	}
	num, _ := strconv.Atoi(string(ip[0:1]))
	if num < 1 {
		return
	}
	if len(ip) < 7 || len(ip) > 15 {
		return
	}
	//垃圾ip 卡死
	if ip == "20.205.243.166" || ip == "175.178.31.156" || ip == "157.255.77.80" {
		return
	}

	s3 := string(ip[0:3])
	if s3 == "127" || s3 == "10." {
		return
	}

	s7 := string(ip[0:7])
	if s7 == "192.168" || s7 == "172.16." || s7 == "172.17." || s7 == "172.18." || s7 == "172.19." || s7 == "172.20." || s7 == "172.21." || s7 == "172.22." || s7 == "172.23." || s7 == "172.24." || s7 == "172.25." || s7 == "172.26." || s7 == "172.27." || s7 == "172.28." || s7 == "172.29." || s7 == "172.30." || s7 == "172.31." {
		return
	}
	goc(func() {
		setips(ip)
		if IPS[ip].utime+1000*60*2 < timems() {
			IPS[ip].utime = timems()
			go httpHead(host, ip, 1000)
		}
	})
}

// ICMP ping
func ping(host string, ip string) {
	ts := timems()
	laddr := net.IPAddr{IP: net.ParseIP("0.0.0.0")} // 得到本机的IP地址结构
	raddr, errxy := net.ResolveIPAddr("ip", ip)     // 解析域名得到 IP 地址结构
	if errxy != nil {
		return
	}
	conn, err := net.DialIP("ip4:icmp", &laddr, raddr)
	if err != nil {
		return
	}
	defer conn.Close()
	recv := make([]byte, 1024)
	buf := []byte{8, 0, 247, 255, 0, 0, 0, 0}

	conn.Write(buf)
	conn.SetReadDeadline((time.Now().Add(1 * 1000 * time.Millisecond)))
	_, err3 := conn.Read(recv)
	pingMs := timems() - ts
	if err3 != nil {
		pingMs = 0
	}
	goc(func() {
		//处理结果
		setips(ip)
		sethost(host)
		IPS[ip].pingMs = pingMs
		if pingMs > 0 {
			HOST[host].ips[ip] = timems()
			IPS[ip].utime = timems()
		}

		setMs(IPS[ip])
	})
}

// http head
func httpHead(host string, ip string, timeout int64) {
	// return //暂时不用
	ts := timems()
	conn, err := net.DialTimeout("tcp", ip+":80", time.Duration(timeout)*time.Millisecond) // timeout
	tcpMs := timems() - ts
	if err != nil {
		if tcpMs > timeout-10 || tcpMs < 2 {
			tcpMs = 0         //给了的时间 如果时间在前答复 证明服务器通信时间就是这个
			go ping(host, ip) //重试Ping
		}
	} else {
		defer conn.Close()
	}
	goc(func() {
		//处理结果
		setips(ip)
		if tcpMs > 0 {
			sethost(host)
			HOST[host].ips[ip] = timems()
			IPS[ip].utime = timems()
		}
		IPS[ip].tcpMs = tcpMs
		setMs(IPS[ip])
	})
	return
	conn.Write([]byte("HEAD / HTTP/1.1\r\nHost: " + host + "\r\nUser-Agent: Mozilla/5.0\r\nAccept: */*\r\nContent-Length: 0\r\n\r\n"))
	conn.SetReadDeadline((time.Now().Add(time.Millisecond * 1000 * 16)))
	buf := make([]byte, 1024)
	len1, err := conn.Read(buf)
	httpMs := timems() - ts
	if err != nil || len1 < 4 || string(buf[:4]) != "HTTP" {
		httpMs = 0
	}
	goc(func() {
		//处理结果
		setips(ip)
		sethost(host)
		if httpMs > 0 {
			HOST[host].ips[ip] = timems()
			IPS[ip].utime = timems()
		}
		IPS[ip].httpMs = httpMs
		setMs(IPS[ip])
	})
}

// 获取毫秒
func timems() int64 {
	return time.Now().UnixNano() / 1e6
}

// 如果不存在则初始化
func sethost(host string) {
	_, err := HOST[host]
	if !err {
		HOST[host] = &HostInfo{
			ips:   map[string]int64{},
			utime: 0,
			ysip:  map[string]string{},
		}
	}
}

// 如果不存在则初始化
func setips(ip string) {
	_, err := IPS[ip]
	if !err {
		IPS[ip] = &IpInfo{
			tcpMs:  0,
			httpMs: 0,
			pingMs: 0,
			ms:     0,
			utime:  0,
		}
	}
}

// 给每个线程暴力加锁 保证线程安全
func goc(fun func()) {
	//go (func() {
	lock.Lock()
	//defer lock.Unlock()
	fun()
	lock.Unlock()
	//})()
}

// http域名解析"223.6.6.6","80"
func host2ipHttp(host string, ip string, dnshost string, dnsport string, sleep int) {
	time.Sleep(time.Duration(sleep) * time.Nanosecond)

	// return
	//暂时不用
	conn, err := net.DialTimeout("tcp", dnshost+":"+dnsport, 2*1000*time.Millisecond) // 3s timeout
	if err != nil {
		return
	}
	defer conn.Close()
	strx := "GET /resolve?name=" + host + "&type=A&short=1&edns_client_subnet=" + ip + " HTTP/1.1\r\nHost: " + dnshost + "\r\nConnection:keep-alive\r\nUser-Agent: Mozilla/5.0\r\nAccept: */*\r\nContent-Length: 0\r\n\r\n"
	_, err2 := conn.Write([]byte(strx))
	if err2 != nil {
		return
	}
	conn.SetReadDeadline((time.Now().Add(time.Millisecond * 1000 * 2)))
	body := make([]byte, 2048)
	len1, err := conn.Read(body)
	if err != nil || len1 < 3 {
		return
	}
	body = body[:len1]
	ss := string(body)
	ret := strings.Split(ss, "\r\n\r\n")
	if len(ret) < 2 {
		return
	}
	ss = ret[1]
	ss = strings.Replace(ss, "\"", "", -1)
	if len(ss) < 5 {
		return
	}
	ss = ss[1 : len(ss)-1]
	ips := strings.Split(ss, ",")
	for i := 0; i < len(ips); i++ {
		go checkIp(host, ips[i])
	}
}
